﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YJKArchUtils.Utils;
using YJKRevitDimensionText.OneKeyPlanDim.Utility;

namespace YJKRevitDimensionText.OneKeyPlanDim.DimData
{
	public class DbSlopeFloor : DbDimBase
	{
		public DbSlopeFloor(Floor floor)
		{
			this.m_floor = floor;
		}

		public Line SlopeStartLine
		{
			get
			{
				this.AnalysisInfo();
				return this.m_SlopeStartLine;
			}
		}

		public XYZ CenterPoint
		{
			get
			{
				this.AnalysisInfo();
				return GeometryHelper.GeometricCenterOfPlanarFace(this.m_upFaceUpOrDown);
			}
		}

		public bool AnalysisInfo()
		{
			if (!base.IsNeedAnalysisInfo())
			{
				return true;
			}
			try
			{
				this.FloorPlanarFaceUpOrDown(this.m_floor);
				this.GetSlopeStartLineAndTopPoint();
				this.GetSlopeUpDir();
				this.CalSlopeValue();
				List<CurveLoop> list = new List<CurveLoop>();
				foreach (CurveLoop curveLoop in this.m_upFaceUpOrDown.GetEdgesAsCurveLoops())
				{
					CurveLoop xyplaneCurve = CommonInterface.GetXYPlaneCurve(curveLoop);
					list.Add(xyplaneCurve);
				}
				if (this.BIsSlopeFloor())
				{
					OcclusionArea.GetInstance().AddRampCurve(this.m_floor.Id, list);
				}
			}
			catch
			{
				return false;
			}
			return !(this.m_SlopeStartLine == null);
		}

		public override bool CreateSizeDim(Autodesk.Revit.DB.Document doc)
		{
			if (!base.CreateSizeDim(doc))
			{
				return false;
			}
			this.AnalysisInfo();
			this.CreateSizeDimWithLengthDir();
			this.CreateSizeDimWithWidthDir();
			return true;
		}

		private bool CreateSizeDimWithLengthDir()
		{
			Grid grid = null;
			DbAxial dbAxial = null;
			if (base.GetDbAxialWithDir(this.m_SlopeDimDir, out dbAxial))
			{
				double num = 0.0;
				grid = dbAxial.GetGridNearestXZY(this.m_SlopeStartLine.GetEndPoint(0), ref num);
				double num2 = 0.0;
				Grid gridNearestXZY = dbAxial.GetGridNearestXZY(this.m_SlopeStartLine.GetEndPoint(1), ref num2);
				if (Geometry.LessThan(num2, num))
				{
					grid = gridNearestXZY;
				}
				if (Geometry.IsEqual(num, 0.0) || Geometry.IsEqual(num2, 0.0))
				{
					grid = null;
				}
			}
			DetailCurve detailCurveWithPoint = CommonInterface.GetDetailCurveWithPoint(this.m_doc, this.m_SlopeStartLine.GetEndPoint(0), this.m_SlopeDimDir);
			DetailCurve detailCurveWithPoint2 = CommonInterface.GetDetailCurveWithPoint(this.m_doc, this.m_SlopeStartLine.GetEndPoint(1), this.m_SlopeDimDir);
			ReferenceArray referenceArray = new ReferenceArray();
			if (detailCurveWithPoint != null)
			{
				Reference reference = new Reference(detailCurveWithPoint);
				referenceArray.Append(reference);
			}
			if (detailCurveWithPoint2 != null)
			{
				Reference reference = new Reference(detailCurveWithPoint2);
				referenceArray.Append(reference);
			}
			if (grid != null)
			{
				XYZ xyz = (grid.Curve as Line).Project(this.m_SlopeStartLine.GetEndPoint(0)).XYZPoint;
				xyz = new XYZ(xyz.X, xyz.Y, this.m_SlopeStartLine.GetEndPoint(0).Z);
				DetailCurve detailCurveWithPoint3 = CommonInterface.GetDetailCurveWithPoint(this.m_doc, xyz, this.m_SlopeDimDir);
				if (detailCurveWithPoint3 != null)
				{
					Reference reference = new Reference(detailCurveWithPoint3);
					referenceArray.Append(reference);
				}
			}
			Line line = this.m_SlopeStartLine.Clone() as Line;
			double dLength = Common.MMToFeet(600.0) * (double)(this.m_doc.ActiveView.Scale / 100);
			line = CommonInterface.NextDodgeLine(line, -this.m_SlopeDimDir, dLength);
			Dimension dimension = new SizeDimData(this.m_doc, line, referenceArray).CreateDim(true);
			if (dimension == null)
			{
				return false;
			}
			this.SetDimPosition(dimension, line, -this.m_SlopeDimDir);
			return true;
		}

		private bool CreateSizeDimWithWidthDir()
		{
			XYZ xyz = (this.m_SlopeStartLine.GetEndPoint(0) + this.m_SlopeStartLine.GetEndPoint(1)) / 2.0;
			XYZ xyz2 = new XYZ(this.m_maxZPoint.X, this.m_maxZPoint.Y, xyz.Z);
			Grid grid = null;
			DbAxial dbAxial = null;
			if (base.GetDbAxialWithDir(this.m_SlopeStartLine.Direction, out dbAxial))
			{
				double num = 0.0;
				grid = dbAxial.GetGridNearestXZY(xyz2, ref num);
				double num2 = 0.0;
				Grid gridNearestXZY = dbAxial.GetGridNearestXZY(this.m_SlopeStartLine.GetEndPoint(1), ref num2);
				if (Geometry.LessThan(num2, num))
				{
					grid = gridNearestXZY;
				}
				if (Geometry.IsEqual(num, 0.0) || Geometry.IsEqual(num2, 0.0))
				{
					grid = null;
				}
			}
			XYZ dir = this.m_SlopeDimDir.CrossProduct(XYZ.BasisZ);
			DetailCurve detailCurveWithPoint = CommonInterface.GetDetailCurveWithPoint(this.m_doc, xyz2, dir);
			DetailCurve detailCurveWithPoint2 = CommonInterface.GetDetailCurveWithPoint(this.m_doc, this.m_SlopeStartLine.GetEndPoint(1), dir);
			ReferenceArray referenceArray = new ReferenceArray();
			if (detailCurveWithPoint != null)
			{
				Reference reference = new Reference(detailCurveWithPoint);
				referenceArray.Append(reference);
			}
			if (detailCurveWithPoint2 != null)
			{
				Reference reference = new Reference(detailCurveWithPoint2);
				referenceArray.Append(reference);
			}
			if (grid != null)
			{
				XYZ xyz3 = (grid.Curve as Line).Project(xyz2).XYZPoint;
				xyz3 = new XYZ(xyz3.X, xyz3.Y, xyz2.Z);
				DetailCurve detailCurveWithPoint3 = CommonInterface.GetDetailCurveWithPoint(this.m_doc, xyz3, dir);
				if (detailCurveWithPoint3 != null)
				{
					Reference reference = new Reference(detailCurveWithPoint3);
					referenceArray.Append(reference);
				}
			}
			Line line = Line.CreateUnbound(xyz, this.m_SlopeDimDir);
			double dLength = this.m_SlopeStartLine.Length / 2.0 + Common.MMToFeet(600.0) * (double)(this.m_doc.ActiveView.Scale / 100);
			line = CommonInterface.NextDodgeLine(line, dir, dLength);
			Dimension dimension = new SizeDimData(this.m_doc, line, referenceArray).CreateDim(true);
			if (dimension == null)
			{
				return false;
			}
			this.SetDimPosition(dimension, line, dir);
			return true;
		}

		public override bool CreateLevelDim(Autodesk.Revit.DB.Document doc, out List<SingleLevelDimDataInfo> lstSingleLevelDimDataInfo)
		{
			if (!base.CreateLevelDim(doc, out lstSingleLevelDimDataInfo))
			{
				return false;
			}
			this.AnalysisInfo();
			XYZ xyz = (this.SlopeStartLine.GetEndPoint(0) + this.SlopeStartLine.GetEndPoint(1)) / 2.0 - this.m_SlopeDimDir * (Common.MMToFeet(1500.0) * (double)this.m_doc.ActiveView.Scale / 100.0);
			if (base.ComponentInSlopePlanarFace != null)
			{
				xyz = CommonInterface.PtInPlanarFaceInDir(xyz, base.ComponentInSlopePlanarFace, XYZ.BasisZ);
			}
			FamilyInstance familyInstance = new LevelDimData(this.m_doc)
			{
				PtDimLocation = xyz,
				DimVal = base.FloorLevelVal
			}.CreateLevelDim();
			AnnotationSymbol annotationSymbol = null;
			if (familyInstance != null)
			{
				annotationSymbol = (familyInstance as AnnotationSymbol);
			}
			if (annotationSymbol != null)
			{
				SingleLevelDimDataInfo singleLevelDimDataInfo = new SingleLevelDimDataInfo(annotationSymbol);
				if (base.ComponentInSlopePlanarFace != null)
				{
					singleLevelDimDataInfo.LevelVal = xyz.Z;
				}
				else
				{
					singleLevelDimDataInfo.LevelVal = base.dFloorLevelVal;
				}
				singleLevelDimDataInfo.LadderLineLength = this.SlopeStartLine.Length;
				singleLevelDimDataInfo.DimDir = this.SlopeStartLine.Direction;
				singleLevelDimDataInfo.PtLocation = xyz;
				singleLevelDimDataInfo.bStepDownDim = false;
				singleLevelDimDataInfo.m_LstElementId.Add(this.m_floor.Id);
				lstSingleLevelDimDataInfo.Add(singleLevelDimDataInfo);
			}
			return false;
		}

		public override bool CreateSlopeDim(Autodesk.Revit.DB.Document doc)
		{
			if (!base.CreateSlopeDim(doc))
			{
				return false;
			}
			this.AnalysisInfo();
			if (this.m_SlopeStartLine == null || this.m_SlopeStartLine == null)
			{
				return false;
			}
			XYZ ptStart = (this.m_SlopeStartLine.GetEndPoint(0) + this.m_SlopeStartLine.GetEndPoint(1)) / 2.0;
			FamilyInstance familyInstance = new SlopeDimData(this.m_doc)
			{
				PtStart = ptStart,
				SlopeDimDir = this.m_SlopeDimDir,
				DimVal = this.m_strSlopeValue
			}.CreateSlopeDim();
			if (familyInstance == null)
			{
				return false;
			}
			base.SetSlopeOcclusionArea(familyInstance);
			return true;
		}

		public PlanarFace FloorPlanarFaceUpOrDown(Floor floor)
		{
			double num = double.MinValue;
			foreach (PlanarFace planarFace in GeometryHelper.GetAllPlanarFace(floor))
			{
				if (Geometry.LessThan(num, planarFace.Area))
				{
					num = planarFace.Area;
					this.m_upFaceUpOrDown = planarFace;
				}
			}
			return this.m_upFaceUpOrDown;
		}

		public bool BIsSlopeFloor()
		{
			return !Geometry.IsEqual(this.m_dAng, 0.0);
		}

		private void SetDimPosition(Dimension newDim, Line lineRef, XYZ dir)
		{
			List<CurveLoop> componentAndSizeAndSlopeOcclusionArea = OcclusionArea.GetInstance().GetComponentAndSizeAndSlopeOcclusionArea();
			List<CurveLoop> sizeDimCurveLoop = OcclusionArea.GetSizeDimCurveLoop(newDim);
			XYZ origin = lineRef.Origin;
			XYZ ptEnd = origin;
			List<CurveLoop> list = new List<CurveLoop>();
			for (int i = 0; i < 3; i++)
			{
				ptEnd = CommonInterface.GetNextPositionByOffset(i, Common.MMToFeet(300.0), origin, dir);
				list = CommonInterface.MoveLstCurve(sizeDimCurveLoop, origin, ptEnd);
				bool flag = false;
				using (List<CurveLoop>.Enumerator enumerator = list.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						if (CommonInterface.IsExistOcclusion(enumerator.Current, componentAndSizeAndSlopeOcclusionArea))
						{
							flag = true;
							break;
						}
					}
				}
				if (!flag)
				{
					break;
				}
				if (2 == i)
				{
					ptEnd = origin;
					break;
				}
			}
			OcclusionArea.GetInstance().m_lstSizeDimCvLoop.AddRange(list);
			CommonInterface.MoveElement(newDim, origin, ptEnd, this.m_doc);
		}

		private void CalSlopeValue()
		{
			this.m_dAng = this.m_upFaceUpOrDown.FaceNormal.AngleTo(XYZ.BasisZ);
			if (Geometry.LessThan(Math.PI*.5, this.m_dAng))
			{
				this.m_dAng = Math.PI - this.m_dAng;
			}
			double num = Math.Tan(this.m_dAng);
			int num2 = (int)num;
			if (Geometry.IsEqual(num, (double)num2))
			{
				this.m_strSlopeValue = num2.ToString();
			}
			else
			{
				this.m_strSlopeValue = num.ToString("f2");
			}
			this.m_strSlopeValue = "1 : " + this.m_strSlopeValue;
		}

		private void GetSlopeStartLineAndTopPoint()
		{
			List<Curve> allEdgeList = GeometryHelper.GetAllEdgeList(this.m_upFaceUpOrDown);
			List<Line> list = new List<Line>();
			double num = double.MinValue;
			foreach (Curve curve in allEdgeList)
			{
				Line line = curve as Line;
				if (line != null && GeometryHelper.VectorVerticalVector(line.Direction, XYZ.BasisZ))
				{
					list.Add(line);
				}
				double num2 = Geometry.LessThan(curve.GetEndPoint(0).Z, curve.GetEndPoint(1).Z) ? curve.GetEndPoint(1).Z : curve.GetEndPoint(0).Z;
				if (Geometry.LessThan(num, num2))
				{
					num = num2;
					this.m_maxZPoint = (Geometry.LessThan(curve.GetEndPoint(0).Z, curve.GetEndPoint(1).Z) ? curve.GetEndPoint(1) : curve.GetEndPoint(0));
				}
			}
			double num3 = double.MaxValue;
			foreach (Line line2 in list)
			{
				double num4 = Geometry.LessThan(line2.GetEndPoint(0).Z, line2.GetEndPoint(1).Z) ? line2.GetEndPoint(0).Z : line2.GetEndPoint(1).Z;
				if (Geometry.LessThan(num4, num3))
				{
					num3 = num4;
					this.m_SlopeStartLine = line2;
				}
			}
		}

		private void GetSlopeUpDir()
		{
			XYZ xyz = (this.m_SlopeStartLine.GetEndPoint(0) + this.m_SlopeStartLine.GetEndPoint(1)) / 2.0;
			XYZ xyz2 = XYZ.BasisZ.CrossProduct(this.m_SlopeStartLine.Direction).Normalize();
			XYZ xyz3 = xyz + xyz2 * Common.MMToFeet(10000.0);
			XYZ xyz4 = xyz - xyz2 * Common.MMToFeet(10000.0);
			if (Geometry.LessThan(xyz4.DistanceTo(this.m_maxZPoint), xyz3.DistanceTo(this.m_maxZPoint)))
			{
				this.m_SlopeDimDir = (xyz4 - xyz).Normalize();
				return;
			}
			this.m_SlopeDimDir = (xyz3 - xyz).Normalize();
		}

		private Floor m_floor;

		private PlanarFace m_upFaceUpOrDown;

		private XYZ m_SlopeDimDir = XYZ.Zero;

		private XYZ m_maxZPoint = XYZ.Zero;

		private Line m_SlopeStartLine;

		private string m_strSlopeValue = string.Empty;

		private double m_dAng;
	}
}
